package com.util;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public final class LoadPackage {

	private LoadPackage() {

	}

	public static List<Class<?>> getInterfaces(String jarName, String packageName) {

		List<Class<?>> list = new ArrayList<Class<?>>();
		try {
			List<Class<?>> allClasses = getPackageClasses(jarName, packageName);
			for (Class<?> apiClass : allClasses) {

				if (apiClass.isInterface()) {
					list.add(apiClass);
				}
			}
			return list;

		} catch (Exception e) {
			throw new IllegalStateException("Couldn't get interfaces in path " + packageName, e);
		}
	}

	public static List<Class<?>> getClasses(String jarName, String packageName) {
		try {
			return getPackageClasses(jarName, packageName);
		} catch (Exception e) {
			throw new IllegalStateException("Couldn't get classes in path " + packageName, e);
		}
	}

	public static List<Class<? extends Enum<?>>> getEnums(String jarName, String packageName) {

		List<Class<? extends Enum<?>>> list = new ArrayList<Class<? extends Enum<?>>>();
		try {
			List<Class<?>> allClasses = getPackageClasses(jarName, packageName);
			for (Class<?> aClass : allClasses) {

				if (aClass.isEnum()) {

					@SuppressWarnings("unchecked")
					Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) aClass;
					list.add(enumClass);
				}
			}
			return list;

		} catch (Exception e) {
			throw new IllegalStateException("Couldn't get enums in path " + packageName, e);
		}
	}

	private static List<Class<?>> getPackageClasses(String jarName, String packageName) throws IOException, ClassNotFoundException {

		List<Class<?>> classes = new ArrayList<Class<?>>();
		List<String> list = getClasseNamesInPackage(jarName, packageName);
		for (String aClassName : list) {
			Class<?> aClass = Class.forName(aClassName);
			classes.add(aClass);
		}
		return classes;
	}

	public static List<String> getClasseNamesInPackage(String jarName, String packageName) {
		List<String> classes = new ArrayList<String>();

		packageName = packageName.replaceAll("\\.", "/");
		try {
			JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
			JarEntry jarEntry = jarFile.getNextJarEntry();
			while (jarEntry != null) {
				String name = jarEntry.getName();
				if (name.startsWith(packageName) && name.endsWith(".class")) {
					String subPackageName = name.replaceFirst(packageName + "/", "");
					if (!subPackageName.contains("/")) {
						classes.add(name.replaceAll("/", "\\.").replace(".class", ""));
					}
				}
				jarEntry = jarFile.getNextJarEntry();
			}
		} catch (Exception e) {
			throw new IllegalStateException("Couldn't get jar classes", e);
		}
		return classes;
	}
}
